﻿using Blm.Utils.Extensions;
using Blm.VisionCloud.FrameWork.Cached;
using Language.Resource;
using Microsoft.Extensions.Localization;
using Microsoft.Extensions.Options;
using System;
using System.Collections.Generic;
using System.IO;
using System.Net;
using System.Threading.Tasks;
using VisionCloud.Domain.Common;
using VisionCloud.Domain.Options;
using VisionCloud.Domain.Repository.Interface.Sys;
using VisionCloud.Domain.UnitOfWork;
using VisionCloud.Utility;
using static VisionCloud.Service.Sys.CrossEmailService;
using HttpUtility = System.Web.HttpUtility;

namespace VisionCloud.Service.Sys
{
    public class SmsService
    {
        /// <summary>
        /// 缓存注入
        /// </summary>
        private readonly ICached cached;

        public IUnitOfWork UnitOfWork { get; set; }

        public IStringLocalizer<ServiceResource> SLocalizer { set; get; }

        public ISysUserRepository SysUserRepository { get; set; }

        private readonly SmsSettingOption SettingOption;

        public SmsService(IOptions<SmsSettingOption> options, ICached cached)
        {
            if (options == null)
                throw new ArgumentNullException(nameof(options));
            this.cached = cached;
            SettingOption = options.Value;
        }

        private static object smsLocker = new object();

        /// <summary>
        /// 发送短信
        /// </summary>
        /// <param name="phone"></param>
        /// <param name="content"></param>
        /// <returns></returns>
        private string SendSms(string phone, string content)
        {
            content = $"【{SettingOption.Signature}】" + HttpUtility.UrlEncode(content.Trim());
            string postJsonTpl = "\"account\":\"{0}\",\"password\":\"{1}\",\"phone\":\"{2}\",\"report\":\"true\",\"msg\":\"{3}\"";
            string jsonBody = string.Format(postJsonTpl, SettingOption.Account, SettingOption.Password, phone, content);
            string result = DoPostMethodToObj(SettingOption.Account, SettingOption.Password, SettingOption.PostUrl, "{" + jsonBody + "}");//请求地址请登录zz.253.com获取
            return result;
        }

        /// <summary>
        /// 发送限制管理器
        /// </summary>
        public static class PhoneManager
        {
            /// <summary>
            /// 每个邮箱、号码最多每天发送m次
            /// </summary>
            public static int MaxNumPerEmail { get; set; } = 1000;

            /// <summary>
            /// 系统每天最多1000
            /// </summary>
            public static int MaxNumPerDay { get; set; } = 1000;

            /// <summary>
            /// 每个IP每天最大次数
            /// </summary>
            public static int MaxNumPerIp { get; set; } = 1000;

            /// <summary>
            /// 今天发了多少
            /// </summary>
            public static int TotalSend { get; set; } = 0;

            /// <summary>
            /// 每天的邮件发送情况
            /// </summary>
            public static Dictionary<string, int> PhoneSendInfo { get; set; } = new Dictionary<string, int>();

            /// <summary>
            /// 开始时间
            /// </summary>
            public static DateTime StartTime { get; set; } = DateTime.Now;

            /// <summary>
            /// IP地址
            /// </summary>
            public static Dictionary<string, int> IpInfo { get; set; } = new Dictionary<string, int>();
        }

        /// <summary>
        /// 发送短信
        /// 24小时内每个IP只能发送10个，每个号码最多6个，每天最多发200个
        /// </summary>
        /// <param name="ipaddr"></param>
        /// <param name="phone"></param>
        /// <param name="content"></param>
        /// <returns></returns>
        public async Task<string> SendSms(string ipaddr, string phone, string content)
        {
            string result = string.Empty;
            lock (smsLocker)
            {
                #region 请求量限制

                TimeSpan ts = DateTime.Now - PhoneManager.StartTime;
                if (ts.TotalDays >= 1 || PhoneManager.PhoneSendInfo == null)
                {
                    PhoneManager.StartTime = DateTime.Now;
                    PhoneManager.PhoneSendInfo = new Dictionary<string, int>();
                    PhoneManager.IpInfo = new Dictionary<string, int>();
                }
                if (!string.IsNullOrEmpty(ipaddr))
                {
                    if (PhoneManager.IpInfo.ContainsKey(ipaddr))
                    {
                        var sendedNum = PhoneManager.IpInfo[ipaddr];
                        if (sendedNum >= PhoneManager.MaxNumPerIp)
                        {
                            throw new OperationException(string.Format(SLocalizer["YB0214"].Value, sendedNum));
                        }
                        PhoneManager.IpInfo[ipaddr] = sendedNum + 1;
                    }
                    else
                    {
                        PhoneManager.IpInfo.Add(ipaddr, 1);
                    }
                }
                if (PhoneManager.PhoneSendInfo.ContainsKey(phone))
                {
                    var sendedNum = PhoneManager.PhoneSendInfo[phone];
                    if (sendedNum >= PhoneManager.MaxNumPerEmail)
                    {
                        throw new OperationException(string.Format(SLocalizer["YB0225"].Value, sendedNum));
                    }
                    PhoneManager.PhoneSendInfo[phone] = sendedNum + 1;
                }
                else
                {
                    if (phone != null)
                    {
                        PhoneManager.PhoneSendInfo.Add(phone, 1);
                    }
                }

                if (EmailManager.TotalSend >= EmailManager.MaxNumPerDay)
                {
                    throw new OperationException(SLocalizer["YB0216"].Value);
                }

                PhoneManager.TotalSend++;
                #endregion
            }
            try
            {
                result = SendSms(phone, content);
                Logger.Info($"发送短信完毕：发送结果{result}，手机号{phone.SetSensitive()}");
            }
            catch (Exception ex)
            {
                Logger.Error($"发送短信失败：{phone.SetSensitive()} {ex.Message}", ex);
                throw new OperationException(SLocalizer["YB0226"].Value);
            }

            return result;
        }

        /// <summary>
        /// 请求Http发送短信
        /// </summary>
        /// <param name="account"></param>
        /// <param name="password"></param>
        /// <param name="url"></param>
        /// <param name="jsonBody"></param>
        /// <returns></returns>
        private string DoPostMethodToObj(string account, string password, string url, string jsonBody)
        {
            string result = String.Empty;
            HttpWebRequest httpWebRequest = (HttpWebRequest)WebRequest.Create(url);
            httpWebRequest.ContentType = "application/json";
            httpWebRequest.Method = "POST";

            // Create NetworkCredential Object
            NetworkCredential admin_auth = new NetworkCredential(account, password);

            // Set your HTTP credentials in your request header
            httpWebRequest.Credentials = admin_auth;

            // callback for handling server certificates
            ServicePointManager.ServerCertificateValidationCallback = delegate { return true; };

            using (StreamWriter streamWriter = new StreamWriter(httpWebRequest.GetRequestStream()))
            {
                streamWriter.Write(jsonBody);
                streamWriter.Flush();
                streamWriter.Close();
                HttpWebResponse httpResponse = (HttpWebResponse)httpWebRequest.GetResponse();
                using (StreamReader streamReader = new StreamReader(httpResponse.GetResponseStream()))
                {
                    result = streamReader.ReadToEnd();
                }
            }
            return result;
        }
    }
}